package com.crosbymichael.process
{
	import flash.desktop.NativeProcess;
	import flash.desktop.NativeProcessStartupInfo;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.NativeProcessExitEvent;
	import flash.filesystem.File;
	
	/**
	 * Displatched the the native process of packaging a file is complete. 
	 */	
	[Event(name="complete", type="com.crosbymichael.process.PackageEvent.COMPLETE")]
	
	/**
	 * Dispatched on an error of the native process package operation. 
	 */	
	[Event(name="error", type="com.crosbymichael.process.PackageEvent.ERROR")]
	
	/**
	 * Displatched when a file is non existant 
	 */	
	[Event(name="file_error", type="com.crosbymichael.process.PackageEvent.FILEERROR")]
	
	/**
	 * Errors dispatched in native process errors. 
	 */	
	[Event(name="nativeprocess_error", type="com.crosbymichael.process.PackageEvent.NATIVEPROCESSERROR")]
	
	/**
	 * This is run the native process to package the .air file into a native installer.
	 *  
	 * @author Michael Crosby crosbymichael.com
	 * 
	 */	
	public class PackageNativeInstaller extends Sprite
	{
		
		//Event that is dispatched.
		private var ev:PackageEvent;
		
		/**
		 * Used for the complete event. 
		 */		
		private var _filename:String;
		
		public function PackageNativeInstaller()
		{
		}
		
		/**
		 * Package the .air file into a native installer.
		 *  
		 * @param sdkPath nativePath to the sdk's adt
		 * @param airPath nativePath to the .air file to be packaged
		 * @param outputName The file name for the native installer
		 * @param outputPath This is where the user wants the native installer to be placed on their file system.
		 * @param outputExt The extension used for the native installer
		 * 
		 */			
		public function packageApp(sdkPath:String, 
								   airPath:String, 
								   outputName:String,
								   outputPath:String,
								   outputExt:String):void {
			try {
				var nativeProcessInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
				//Path to the file that is going to be used in the native process.
				var sF:File = _sdkFile(sdkPath);;
				if (sF) {
					nativeProcessInfo.executable = sF; 
				} else {
					
					//Exit funcion.
				}
				//Arguments that will be passed to the native process.
				nativeProcessInfo.arguments = 
					_processArguments(airPath, 
					outputName, 
					outputPath, 
					outputExt);
				
				_filename = outputName;
				
				var process:NativeProcess = new NativeProcess();
				
				//Add event listeners for end of process and errors.
				process.addEventListener(IOErrorEvent.STANDARD_ERROR_IO_ERROR, nativeIoError);
				process.addEventListener(IOErrorEvent.STANDARD_INPUT_IO_ERROR, inputIoError);
				process.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, outputIoError);
				process.addEventListener(NativeProcessExitEvent.EXIT, nativeExit);
				
				process.start(nativeProcessInfo);
				
			} catch (e:Error) { //Catch error from the creation of these native process objs.
				ev = new PackageEvent("error");
				ev.error = "Error creating native process objects. " + e.message;
				dispatchEvent(ev);
			}
			
		}
		
		/**
		 * Event for when the native process is complete and shut off. 
		 * @param e
		 * 
		 */		
		private function nativeExit(e:NativeProcessExitEvent):void
		{
			ev = new PackageEvent("native_exit");
			ev.filename = _filename;
			dispatchEvent(ev);
		}
		
		/**
		 * Error in the native process input.
		 *  
		 * @param e IOErrorEvnet obj.
		 * 
		 */		
		private function inputIoError(e:IOErrorEvent):void
		{
			ev = new PackageEvent("native_error");
			ev.error = "native process input error";
			dispatchEvent(ev);
		}
		
		/**
		 * Error on the native process output.
		 *  
		 * @param e
		 * 
		 */		
		private function outputIoError(e:IOErrorEvent):void
		{
			ev = new PackageEvent("native_error");
			ev.error = "native process output error";
			dispatchEvent(ev);	
		}
		
		/**
		 * Standard native process error event.
		 *  
		 * @param e
		 * 
		 */		
		private function nativeIoError(e:IOErrorEvent):void
		{
			ev = new PackageEvent("native_error");
			ev.error = "native process standard error";
			dispatchEvent(ev);
		}
		
		/**
		 * Converts the nativePath of the sdk file into a valid file obj.  
		 * If the file does not exist, an file_error is dispatched.
		 *  
		 * @param sdkPath NativePath to the adt file.
		 * 
		 * @return File object for the adt file.  If not exists, return nothing and throw file_error. 
		 * 
		 */		
		private function _sdkFile(sdkPath:String):File {
			var f:File = new File(sdkPath);
			if (f.exists) {
				return f;
			} else {
				ev = new PackageEvent("file_error");
				ev.error = "sdk file path non existant.";
				dispatchEvent(ev);
				return null;
			}
			
		}
		
		private function _processArguments(airPath:String, 
										   outputName:String,
										   outputPath:String,
										   outputExt:String):Vector.<String> {
			var args:Vector.<String> = new Vector.<String>;
			
			args.push("-package");
			args.push("-target");
			args.push("native");
			args.push(outputPath + outputName + outputExt);
			args.push(airPath);
			
			return args;
		}
		
	}
}